// Copyright 2008 Thiago H. de Paula Figueiredo
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package br.com.arsmachina.module.ioc;

import org.apache.tapestry5.ioc.MappedConfiguration;
import org.apache.tapestry5.ioc.OrderedConfiguration;
import org.apache.tapestry5.ioc.ServiceBinder;
import org.apache.tapestry5.ioc.annotations.Match;
import org.apache.tapestry5.ioc.services.AspectDecorator;
import org.hibernate.SessionFactory;

import br.com.arsmachina.module.factory.ControllerFactory;
import br.com.arsmachina.module.factory.DAOFactory;
import br.com.arsmachina.module.factory.impl.HibernateDAOFactory;
import br.com.arsmachina.module.service.ControllerSource;
import br.com.arsmachina.module.service.DAOSource;
import br.com.arsmachina.module.service.ModuleService;
import br.com.arsmachina.module.service.PrimaryKeyTypeService;
import br.com.arsmachina.module.service.internal.JavassistMethodAdvice;

/**
 * Tapetry-IoC module class for Application Module-Hibernate.
 * 
 * @author Thiago H. de Paula Figueiredo
 */
public class ApplicationModuleHibernateModule {

	/**
	 * Binds the {@link JavassistMethodAdvice} service.
	 * 
	 * @param binder a {@link ServiceBinder}.
	 */
	public static void bind(ServiceBinder binder) {
		binder.bind(JavassistMethodAdvice.class);
	}

	/**
	 * Decorates some services to solve the Javassist proxy problem.
	 * 
	 * @param daoFactory a {@link DAOFactory}.
	 * @param aspectDecorator an {@link AspectDecorator}.
	 * @return a decorated {@link DAOFactory}.
	 */
	@Match( { "ControllerFactory", "ControllerFactory", "ControllerSource",
			"DAOSource", "ModuleService", "PrimaryKeyTypeService" })
	public static <T> T decorateToSolveJavassistProxyProblem(
			Class<T> serviceInterface, T delegate, String serviceId,
			AspectDecorator aspectDecorator, JavassistMethodAdvice advice) {

		T service = null;

		if (serviceInterface.equals(ControllerFactory.class)
				|| serviceInterface.equals(DAOFactory.class)
				|| serviceInterface.equals(ControllerSource.class)
				|| serviceInterface.equals(DAOSource.class)
				|| serviceInterface.equals(ModuleService.class)
				|| serviceInterface.equals(PrimaryKeyTypeService.class)) {

			service =
				aspectDecorator.build(serviceInterface, delegate, advice,
						"JavassistMethodAdvice");
		}

		return service;

	}

	/**
	 * Decorates the {@link ControllerFactory} service to solve the Javassist
	 * proxy problem.
	 * 
	 * @param daoFactory a {@link ControllerFactory}.
	 * @param aspectDecorator an {@link AspectDecorator}.
	 * @return a decorated {@link ControllerFactory}.
	 */
	public static ControllerFactory decorateControllerFactory(
			ControllerFactory daoFactory, AspectDecorator aspectDecorator,
			JavassistMethodAdvice advice) {

		return aspectDecorator.build(ControllerFactory.class, daoFactory,
				advice, "JavassistMethodAdvice");

	}

	/**
	 * Contributes {@link HibernateDefaultDAOFactory} to the {@link DAOFactory}
	 * service.
	 * 
	 * @param configuration an {@link OrderedConfiguration} of
	 *            {@link DAOFactory}'s.
	 * @param sessionFactory a {@link SessionFactory}.
	 */
	public static void contributeDAOFactory(
			OrderedConfiguration<DAOFactory> configuration,
			SessionFactory sessionFactory) {

		configuration.add("hibernate", new HibernateDAOFactory(sessionFactory),
				"after:*");

	}

	/**
	 * Defines the value for the
	 * {@link ApplicationModuleModule#DAO_IMPLEMENTATION_SUBPACKAGE_SYMBOL} to
	 * <code>hibernate</code>.
	 * 
	 * @param configuration
	 */
	public static void contributeApplicationDefaults(
			MappedConfiguration<String, String> configuration) {

		configuration.add(
				ApplicationModuleModule.DAO_IMPLEMENTATION_SUBPACKAGE_SYMBOL,
				"hibernate");

	}

//	/**
//	 * Contributes {@link HibernatePrimaryKeyTypeService} to the
//	 * {@link PrimaryKeyTypeService} service.
//	 * 
//	 * @param configuration an {@link OrderedConfiguration} of
//	 *            {@link PrimaryKeyTypeService}'s.
//	 * @param sessionFactory a {@link SessionFactory}.
//	 */
//	public static void contributePrimaryKeyTypeService(
//			OrderedConfiguration<PrimaryKeyTypeService> configuration,
//			SessionFactory sessionFactory, AspectDecorator aspectDecorator,
//			JavassistMethodAdvice advice) {
//
//		PrimaryKeyTypeService service =
//			new HibernatePrimaryKeyTypeService(sessionFactory);
//
//		service =
//			aspectDecorator.build(PrimaryKeyTypeService.class, service, advice,
//					"JavassistMethodAdvice");
//
//		configuration.add("hibernate", service, "before:default");
//
//	}
//	
//	/**
//	 * Contributes {@link HibernatePrimaryKeyEncoderFactory} to the
//	 * {@link PrimaryKeyEncoderFactory} service.
//	 * 
//	 * @param configuration an {@link OrderedConfiguration} of
//	 *            {@link PrimaryKeyEncoderFactory}'s.
//	 * @param sessionFactory a {@link SessionFactory}.
//	 */
//	public static void contributePrimaryKeyEncoderFactory(
//			OrderedConfiguration<PrimaryKeyEncoderFactory> configuration,
//			SessionFactory sessionFactory, AspectDecorator aspectDecorator,
//			JavassistMethodAdvice advice) {
//
//		PrimaryKeyEncoderFactory service =
//			new HibernatePrimaryKeyEncoderFactory(sessionFactory);
//
//		service =
//			aspectDecorator.build(PrimaryKeyEncoderFactory.class, service, advice,
//					"JavassistMethodAdvice");
//
//		configuration.add("hibernate", service, "before:default");
//
//	}

}
